//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Xml;
using OpenLS.Core.Serialization;
using OpenLS.Spreadsheet.Collections;
using OpenLS.Spreadsheet.Expressions;
using OpenLS.Spreadsheet.Office2003;

namespace OpenLS.Spreadsheet
{
    partial class Cell
    {
        internal int ReadXmlSpreadsheet(ReadContext context, int availableIndex)
        {
            int result;
            using (ReadContext c = context.Read("Cell"))
            {
                string styleId = c.GetOptionalString(c.Namespace + "StyleID");
                if (styleId != null)
                {
//\\                    Debug.WriteLine(styleId);
                    FormattingRecord = c.GetData<StyleLookup>()[styleId];
                }
                Column = Worksheet.Columns[c.GetOptionalInteger(c.Namespace + "Index", availableIndex + 1) - 1];
                {
                    int columnSpan = c.GetOptionalInteger(c.Namespace + "MergeAcross", 0)+1;
                    result = columnSpan ;
                    int rowSpan = c.GetOptionalInteger(c.Namespace + "MergeDown", 0)+1;
                    if (columnSpan != 1 || rowSpan != 1)
                    {
                        c.GetData<CellMerger>().Add(new RangeAddress(
                            new CellAddress(this), new CellAddress(this) + new CellRelativeAddress(rowSpan - 1, columnSpan - 1)));
                    }
                }
                string formula = c.GetOptionalString(c.Namespace + "Formula");
                if (formula != null)
                {
                    WorkbookResolver resolver = c.GetData<WorkbookResolver>();
                    resolver.AddFormula(this, formula);
                }
                
                if (c.ReaderLocalName == "Data")
                {
                    using (ReadContext data = c.Read("Data"))
                    {
                        CellType2003 t = data.GetEnum<CellType2003>(data.Namespace + "Type");
                        RichTextParagraph paragraph = null;
                        Stack<Action<RichTextRun>> actions = null;
                        string lastString = null;
                        while (data.ReaderLocalName != null)
                        {
                            if (string.IsNullOrEmpty(data.ReaderLocalName))
                            {
                                string s = data.ReadString();
                                switch (t)
                                {
                                    case CellType2003.Boolean:
                                        SetValueAndFormat(GetBooleanValue(s), false); break;
                                    case CellType2003.DateTime:
                                        SetValueAndFormat(XmlConvert.ToDateTime(s, XmlDateTimeSerializationMode.Unspecified), false); break;
                                    case CellType2003.Error:
                                        SetValueAndFormat(Error.Parse(s), false); break;
                                    case CellType2003.Number:
                                        SetValueAndFormat(double.Parse(s, CultureInfo.InvariantCulture), false); break;
                                    case CellType2003.String:
                                        {
                                            if (paragraph != null)
                                                paragraph.Runs.Add(new RichTextRun(s));
                                            else
                                            {
                                                Value = s;
                                                lastString  = s;
                                            }
                                               break;
                                        }
                                }
                            }
                            else
                            {
                                if (paragraph == null)
                                    paragraph = new RichTextParagraph();
                                if (actions == null)
                                    actions  = new Stack<Action<RichTextRun>>();
                                if (lastString != null)
                                {
                                    Value = null;
                                    lastString = null;
                                    paragraph.Runs.Add(new RichTextRun(lastString));
                                }
                                else
                                {
                                    ReadElement(data, actions, paragraph);
                                }
                            }
                        }
                        if (paragraph != null)
                            RichValue = paragraph;
                    }
                }
                c.EatForNow("Comment");
                while (c.ReaderLocalName == "NamedCell")
                    c.EatForNow("NamedCell");
                c.EatForNow("PhoneticText");
                c.EatForNow("SmartTag");
            }
            return result;
        }
        void ReadElement (ReadContext context, Stack<Action<RichTextRun>> actions, RichTextParagraph owner)
        {
            while (context.ReaderLocalName != null)
            {
                if (context.ReaderLocalName == "")
                {
                    RichTextRun r = new RichTextRun(context.ReadString());
                    foreach (Action<RichTextRun> a in actions)
                        a(r);
                    owner.Runs.Add(r);
                    continue;
                }

                switch (context.ReaderLocalName)
                {
                    case "I":
                        actions.Push(delegate(RichTextRun r) { r.IsItalic = true; }); break;
                    case "B":
                        actions.Push(delegate(RichTextRun r) { r.IsBold = true; }); break;
                    case "U":
                        UnderlineType t = UnderlineType.Single;
                        switch (context.GetOptionalString("Style"))
                        {
                            case "text-underline:double": t = UnderlineType.Double; break;
                            case "text-underline:single-accounting": t = UnderlineType.SingleAccounting; break;
                            case "text-underline:double-accounting": t = UnderlineType.DoubleAccounting; break;
                        }
                        actions.Push(delegate(RichTextRun r)
                        {
                            r.Underline = t;
                        }); break;
                    case "S":
                        actions.Push(delegate(RichTextRun r) { r.Strike = true; }); break;
                    case "Sub":
                        actions.Push(delegate { }); break;
                    case "Sup":
                        actions.Push(delegate { }); break;
                    case "Span":
                        actions.Push(delegate { }); break;
                    case "Font":
                        actions.Push(
                            delegate {
                            }
                            ); break;
                    default:
                        throw new NotSupportedException();
                }
                using (ReadContext c = context.Read(XmlSpreadsheetConstants.HtmlNamespace  + context.ReaderLocalName ))
                {
                    ReadElement(c, actions, owner);
                }

                actions.Pop();

            }

        }

        private void notifyFormulaChanged()
        {
            notifyNonRecordPropertyChanged(CellProperties.Formula);
            notifyNonRecordPropertyChanged(CellProperties.LocalizedFormula);
            //notifyNonRecordPropertyChanged(CellProperties.HasArrayFormula);
            notifyNonRecordPropertyChanged(CellProperties.ArrayFormulaRange);
        }

        internal void ForgetDependents()
        {
            if (_expression != null)
            {
                foreach (IDependencyNode c in _expression.GetPrecedents(new CellEvaluationContext(this)))
                {
                    c.RemoveDependent(this);
                }
            }
        }
    }
}
